import Mesh = laya.d3.resource.models.Mesh;
import Vector2 = Laya.Vector2;
import Vector3 = Laya.Vector3;
import Vector4 = Laya.Vector4;

export default class LMath {
    public static Clamp01(value: number) {
        if (value < 0)
            value = 0;
        if (value > 1)
            value = 1;
        return value;
    }
}

export class LPhysics {
    public static AccelerationofGravity = 10.0;
}

export class LGeometry {
    public static IsPointInsideTriangle(point: Vector3, t0: Vector3, t1: Vector3, t2: Vector3, planenormal: Vector3): boolean {
        if (LVector3.Cross(LVector3.Subtract(t1, t0), LVector3.Subtract(t2, t0)) == LVector3.zero) {
            return false;
        }
        let pointTo0: Vector3 = LVector3.Subtract(t0, point);
        let pointTo1: Vector3 = LVector3.Subtract(t1, point);
        let pointTo2: Vector3 = LVector3.Subtract(t2, point);
        if (Vector3.dot(LVector3.Cross(pointTo0, pointTo1), planenormal) > 0 ||
            Vector3.dot(LVector3.Cross(pointTo1, pointTo2), planenormal) > 0 ||
            Vector3.dot(LVector3.Cross(pointTo2, pointTo0), planenormal) > 0) {
            return false;
        }
        return true;
    }
    
    //centroid methed 
    public static IsPointInsideTriangle2(A: Vector3, B: Vector3, C: Vector3, P: Vector3): boolean {
        let v0: Vector3 = LVector3.Subtract(C,A);
        let v1: Vector3 = LVector3.Subtract(B, A);
        let v2: Vector3 = LVector3.Subtract(P, A);

        let dot00: number = Vector3.dot(v0, v0);
        let dot01: number = Vector3.dot(v0, v1);
        let dot02: number = Vector3.dot(v0, v2);
        let dot11: number = Vector3.dot(v1, v1);
        let dot12: number = Vector3.dot(v1, v2);

        let inverDeno = 1 / (dot00 * dot11 - dot01 * dot01);
        let u = (dot11 * dot02 - dot01 * dot12) * inverDeno;
        if (u < 0 || u > 1) {
            return false;
        }
        let v = (dot00 * dot12 - dot01 * dot02) * inverDeno;
        if (v < 0 || v > 1) {
            return false;
        }
        return u + v <= 1;
    }
}

export class LVector3 {
    public static Log(a: Vector3, pre:string = "") {
        console.log(pre + a.x + "," + a.y + "," + a.z);
    }

    private static m_Zero: Vector3;
    public static get zero(): Vector3{
        if (this.m_Zero == null)
            this.m_Zero = new Vector3(0, 0, 0);
        return this.m_Zero;
    }
    private static m_One:Vector3;
    public static get one():Vector3{
        if(this.m_One == null)
            this.m_One = new Vector3(1,1,1);
        return this.m_One;
    }

    public static get up(): Vector3 {
        return new Vector3(0, 1, 0);
    }
    public static get forward():Vector3{
        return new Vector3(0,0,1);
    }
    public static Normalize(org: Vector3): Vector3 {
        //let out = new Vector3();
        Vector3.normalize(org, org);
        return org;
    }
    public static Invert(org: Vector3): Vector3{
        let result = new Vector3();
        result.x = -org.x;
        result.y = -org.y;
        result.z = -org.z;
        return result;
    }
    public static Clone(org: Vector3) {
        let result = new Vector3();
        result.x = org.x;
        result.y = org.y;
        result.z = org.z;
        return result;
    }
    public static Copy(org: Vector3, des: Vector3) {
        des.x = org.x; des.y = org.y; des.z = org.z;
    }
    public static Lerp(a: Vector3, b: Vector3, t: number) {
        let result = new Vector3();
        Vector3.lerp(a, b, t, result);
        return result;
    }
    public static Add(a: Vector3, b: Vector3): Vector3 {
        let result = new Vector3();
        Vector3.add(a, b, result);
        return result;
    }
    public static Subtract(a: Vector3, b: Vector3): Vector3 {
        let result = new Vector3();
        Vector3.subtract(a, b, result);
        return result;
    }
    public static Cross(a: Vector3, b: Vector3): Vector3 {
        let result = new Vector3();
        Vector3.cross(a, b, result);
        return result;
    }
    public static Multiply(a: number, b: Vector3): Vector3 {
        return new Vector3(b.x * a, b.y * a, b.z * a);
    }
    public static MatrixMult(a: Laya.Matrix4x4, b: Vector3): Vector3 {
        let out: Vector3 = new Vector3();
        out.x = b.x * a.elements[0] + b.y * a.elements[4] + b.z * a.elements[8] + 1 * a.elements[12];
        out.y = b.x * a.elements[1] + b.y * a.elements[5] + b.z * a.elements[9] + 1 * a.elements[13];
        out.z = b.x * a.elements[2] + b.y * a.elements[6] + b.z * a.elements[10] + 1 * a.elements[14];
        let w: number = b.x * a.elements[3] + b.y * a.elements[7] + b.z * a.elements[11] + 1 * a.elements[15];
        out.x /= w;
        out.y /= w;
        out.z /= w;
        return out;
    }
    public static MatrixMultDirect(a: Laya.Matrix4x4, b: Vector3): Vector3 {
        let out: Vector3 = new Vector3();
        out.x = b.x * a.elements[0] + b.y * a.elements[4] + b.z * a.elements[8];
        out.y = b.x * a.elements[1] + b.y * a.elements[5] + b.z * a.elements[9];
        out.z = b.x * a.elements[2] + b.y * a.elements[6] + b.z * a.elements[10];
        Vector3.normalize(out, out);
        return out;
    }
    public static Matrix3x3Mult(a: Laya.Matrix3x3, b: Vector3): Vector3 {
        let out: Vector3 = new Vector3();
        out.x = b.x * a.elements[0] + b.y * a.elements[3] + b.z * a.elements[6];
        out.y = b.x * a.elements[1] + b.y * a.elements[4] + b.z * a.elements[7];
        out.z = b.x * a.elements[2] + b.y * a.elements[5] + b.z * a.elements[8];
        return out;
    }
}

export class LVector4 {
    public static Normalize(org: Vector4): Vector4 {
        //let out = new Vector4();
        Vector4.normalize(org, org);
        return org;
    }
}

export class LVector2 {
    public static Normalize(org: Vector2): Vector2 {
        //let out = new Vector4();
        Vector2.normalize(org, org);
        return org;
    }
    public static Multiply(a: number, b: Vector2): Vector2 {
        return new Vector2(b.x * a, b.y * a);
    }
    public static Add(a: Vector2, b: Vector2): Vector2 {
        let result = new Vector2();
        result.x = a.x + b.x;
        result.y = a.y + b.y;
        return result;
    }
    public static Subtract(a: Vector2, b: Vector2): Vector2 {
        let result = new Vector2();
        result.x = a.x - b.x;
        result.y = a.y - b.y;
        return result;
    }
}

export class LMatrix4x4{
    public static ShowMatrix(a: Laya.Matrix4x4) {
        let line: string = "[";
        for (let i = 0; i < a.elements.length; ++i) {
            if (i % 4 == 0) {
                if (i != 0)
                    line + ";"
                console.log(line);
                line = "";
            }
            line += a.elements[i] + ",";
        }
        line = line.substring(0, line.length - 1);
        console.log(line + "]");
    }
    public static Set(a: Laya.Matrix4x4, ...arr: number[]) {
        for (let i = 0; i < arr.length; ++i) {
            a.elements[i] = arr[i];
        }
    }
}

export class LMatrix3x3 {
    public static ShowMatrix(a: Laya.Matrix3x3) {
        let line: string = "[";
        for (let i = 0; i < a.elements.length; ++i) {
            if (i % 3 == 0) {
                if (i != 0)
                    line + ";"
                console.log(line);
                line = "";
            }
            line += a.elements[i] + ",";
        }
        line = line.substring(0, line.length - 1);
        console.log(line + "]");
    }
    public static Set(a: Laya.Matrix3x3, ...arr: number[]) {
        for (let i = 0; i < arr.length; ++i) {
            a.elements[i] = arr[i];
        }
    }
}